package com.cn.algorithm.one.list.test;

import com.cn.algorithm.one.list.LinkedList;
import com.cn.algorithm.one.list.List;

import java.util.Objects;

public class LinkedListK<E> extends AbstractListK<E> {

    Node<E> first;

    Node<E> last;


    @Override
    public void clear() {
        first = null;
        last = null;
        size = 0;
    }

    @Override
    public E get(int index) {
        Node<E> node = node(index);
        return node == null ? null : node.element;
    }

    @Override
    public E set(int index, E element) {
        Node<E> node = node(index);
        if (node == null) { // index在0的位置
            throw new IndexOutOfBoundsException("elements is null");
        }
        E oldElement = node.element;
        node.element = element;
        return oldElement;
    }

    @Override
    public void add(int index, E element) {
        checkIndexForAdd(index);
        if (size == index) {
            Node<E> lastNode = new Node<>(element, last, null);
            if (size == 0) {
                first = last = lastNode;
                last.prev = first;
                first.next = last;
            } else {
                last.next = lastNode;
                last = lastNode;
            }
        } else {
            Node<E> next = node(index);
            Node<E> prev = next.prev;
            Node<E> newNode = new Node<>(element, prev, next);
            next.prev = newNode;
            if (index == 0) {
                first = newNode;
            } else {
                prev.next = newNode;
            }
        }
        size++;
    }

    @Override
    public void add(E element) {
        add(size, element);
    }

    @Override
    public E remove(int index) {
        checkIndex(index);
        Node<E> removeNode = node(index);
        if (removeNode == null) {
            return null;
        }
        E oldElement = removeNode.element;
        Node<E> next = removeNode.next;
        Node<E> prev = removeNode.prev;
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
        }
        if (prev == null) {
            first = last;
        } else {
            prev.next = next;
        }
        size--;
        return oldElement;
    }

    @Override
    public boolean contains(E element) {
        return index(element) >= 0;
    }

    @Override
    public int index(E element) {
        Node<E> node = first;
        for (int i = 0; i < size; i++) {
            if (Objects.equals(element, node.element)) {
                return i;
            }
            node = node.next;
        }
        return -1;
    }

    public Node<E> node(int index) {
        checkIndex(index);
        Node<E> node = first;
        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        return node;
    }

    public static class Node<E> {

        E element;

        Node<E> prev;

        Node<E> next;

        public Node(E element, Node<E> prev, Node<E> next) {
            this.element = element;
            this.prev = prev;
            this.next = next;
        }
    }


    public static void main(String[] args) {
        ListK<Integer> list = new LinkedListK<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
        System.out.println(list.size());
        list.remove(3);
        list.remove(7);
        System.out.println(list.size());
        System.out.println(list.set(2,20));
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}
